package junior.db.dao.update;

import junior.db.dao.enums.LikeMode;
import junior.db.dao.enums.Operator;
import org.springframework.util.Assert;

import java.util.ArrayList;
import java.util.List;

/**
 * @author wubo
 * @date 2024/8/30 17:40
 */
public class AbstractUpdateEntityOption<O> extends AbstractUpdateOption<O> {
    protected String[] excludeFields;
    protected List<FieldFilter> fieldFilters;
    
    public AbstractUpdateEntityOption() {
        this(true);
    }
    
    public AbstractUpdateEntityOption(boolean skipNull) {
        super(skipNull);
    }
    
    @Override
    public boolean hasAnyFilter() {
        return super.hasAnyFilter() || fieldFilters.size() > 0;
    }
    
    /**
     * 指定排除更新的字段
     * @param ignoreFields 指定的字段不会被更新
     * @return
     */
    public O excludeUpdateFields(String... ignoreFields) {
        Assert.notEmpty(ignoreFields, "Parameter ignoreFields is required");
        this.excludeFields = ignoreFields;
        return (O) this;
    }
    
    /**
     * <h3>更新条件，更新条件表达式左边是field，右边条件值为此字段对应的每个实体对象的值, 表达式为: field = entity.field</h3>
     * @param field 更新条件字段，同时也是条件值字段，条件值为此字段在实体对象的值
     * @return
     */
    public O eqField(String field) {
        if (fieldFilters == null) {
            fieldFilters = new ArrayList<>();
        }
        fieldFilters.add(new FieldFilter(field, Operator.EQ));
        return (O) this;
    }
    
    /**
     * <h3>更新条件，更新条件表达式左边是field，右边条件值为此字段对应的每个实体对象的值, 表达式为: field != entity.field</h3>
     * @param field 更新条件字段，同时也是条件值字段，条件值为此字段在实体对象的值
     * @return
     */
    public O neqField(String field) {
        if (fieldFilters == null) {
            fieldFilters = new ArrayList<>();
        }
        fieldFilters.add(new FieldFilter(field, Operator.NEQ));
        return (O) this;
    }
    
    /**
     * <h3>更新条件，更新条件表达式左边是field，右边条件值为此字段对应的每个实体对象的值, 表达式为: field > entity.field</h3>
     * @param field 更新条件字段，同时也是条件值字段，条件值为此字段在实体对象的值
     * @return
     */
    public O gtField(String field) {
        if (fieldFilters == null) {
            fieldFilters = new ArrayList<>();
        }
        fieldFilters.add(new FieldFilter(field, Operator.GT));
        return (O) this;
    }
    
    /**
     * <h3>更新条件，更新条件表达式左边是field，右边条件值为此字段对应的每个实体对象的值, 表达式为: field < entity.field</h3>
     * @param field 更新条件字段，同时也是条件值字段，条件值为此字段在实体对象的值
     * @return
     */
    public O ltField(String field) {
        if (fieldFilters == null) {
            fieldFilters = new ArrayList<>();
        }
        fieldFilters.add(new FieldFilter(field, Operator.LT));
        return (O) this;
    }
    
    /**
     * <h3>更新条件，更新条件表达式左边是field，右边条件值为此字段对应的每个实体对象的值, 表达式为: field >= entity.field</h3>
     * @param field 更新条件字段，同时也是条件值字段，条件值为此字段在实体对象的值
     * @return
     */
    public O gteField(String field) {
        if (fieldFilters == null) {
            fieldFilters = new ArrayList<>();
        }
        fieldFilters.add(new FieldFilter(field, Operator.GTE));
        return (O) this;
    }
    
    /**
     * <h3>更新条件，更新条件表达式左边是field，右边条件值为此字段对应的每个实体对象的值, 表达式为: field <= entity.field</h3>
     * @param field 更新条件字段，同时也是条件值字段，条件值为此字段在实体对象的值
     * @return
     */
    public O lteField(String field) {
        if (fieldFilters == null) {
            fieldFilters = new ArrayList<>();
        }
        fieldFilters.add(new FieldFilter(field, Operator.LTE));
        return (O) this;
    }
    
    /**
     * <h3>更新条件，更新条件表达式左边是field，右边条件值为此字段对应的每个实体对象的值, 表达式为: field like '%' + entity.field + '%'</h3>
     * @param field 更新条件字段，同时也是条件值字段，条件值为此字段在实体对象的值
     * @param likeMode like模式
     * @return
     */
    public O likeField(String field, LikeMode likeMode) {
        if (fieldFilters == null) {
            fieldFilters = new ArrayList<>();
        }
        fieldFilters.add(new FieldFilter(field, Operator.LIKE, likeMode));
        return (O) this;
    }
    
    /**
     * <h3>更新条件，更新条件表达式左边是field，右边条件值为此字段对应的每个实体对象的值, 表达式为: field not like entity.field</h3>
     * @param field 更新条件字段，同时也是条件值字段，条件值为此字段在实体对象的值
     * @param likeMode like模式
     * @return
     */
    public O notLikeField(String field, LikeMode likeMode) {
        if (fieldFilters == null) {
            fieldFilters = new ArrayList<>();
        }
        fieldFilters.add(new FieldFilter(field, Operator.NOT_LIKE, likeMode));
        return (O) this;
    }
    
    /**
     * 更新时加上版本号，用于乐观锁，
     * 见withVersion(versionField, version, skipOnNull)方法
     * @param versionField 版本号字段名
     * @param version 当前记录中的版本号
     * @return
     */
    public O withVersionField(String versionField) {
        this.withUpdateExpression(versionField, "ifNull(${"+versionField+"}, 0) + 1");
        this.eqField(versionField);
        return (O) this;
    }
    
    protected static class FieldFilter {
        String field;
        Operator operator;
        LikeMode likeMode;
        public FieldFilter(String field, Operator operator) {
            this(field, operator, null);
        }
        public FieldFilter(String field, Operator operator, LikeMode likeMode) {
            this.field = field;
            this.operator = operator;
            this.likeMode = likeMode;
        }
    }
}
